import axios from 'axios';

const flowable = axios.create({
  baseURL: '/flowable-rest/service'
});

// ========== Deployments ==========
export async function listDeployments() {
  const { data } = await flowable.get('/repository/deployments');
  return data.data || [];
}

export async function deleteDeployment(id: string) {
  await flowable.delete(`/repository/deployments/${id}`);
}

export async function deployBpmn(file: File) {
  const form = new FormData();
  form.append('file', file, file.name);
  const { data } = await axios.post('/api/flowable/deploy', form, {
    headers: { 'Content-Type': 'multipart/form-data' }
  });
  return data.data;
}

// ========== Definitions ==========
export async function listDefinitions() {
  const { data } = await flowable.get('/repository/process-definitions');
  return data.data || [];
}

// ========== Process Instances ==========
export interface InstanceQueryParams { processDefinitionKey?: string; startedBy?: string; page?: number; pageSize?: number }
export interface InstancePagedResult { items: any[]; total: number; page: number; pageSize: number; }

export async function listInstances(params: InstanceQueryParams = {}): Promise<InstancePagedResult> {
  const page = params.page && params.page > 0 ? params.page : 1;
  const pageSize = params.pageSize && params.pageSize > 0 ? params.pageSize : 20;
  const query: Record<string, any> = {};
  if (params.processDefinitionKey) query.processDefinitionKey = params.processDefinitionKey;
  if (params.startedBy) query.startedBy = params.startedBy;
  query.start = (page - 1) * pageSize;
  query.size = pageSize;
  const { data } = await flowable.get('/runtime/process-instances', { params: query });
  const instances: any[] = data.data || [];
  const total: number = data.total ?? instances.length;
  if (instances.length === 0) {
    return { items: [], total, page, pageSize };
  }
  const missingName = instances.some(i => !i.processDefinitionName);
  if (missingName) {
    const defIds = Array.from(new Set(instances.map(i => i.processDefinitionId).filter(Boolean)));
    const defMap: Record<string, string> = {};
    for (const id of defIds) {
      try {
        const { data: def } = await flowable.get(`/repository/process-definitions/${id}`);
        defMap[id] = def.name || def.id || id;
      } catch {
        defMap[id] = id;
      }
    }
    const enriched = instances.map(i => ({
      ...i,
      processDefinitionName: i.processDefinitionName || defMap[i.processDefinitionId] || i.processDefinitionId
    }));
    return { items: enriched, total, page, pageSize };
  }
  return { items: instances, total, page, pageSize };
}

export async function startProcess(definitionKey: string, businessKey?: string, variables?: Record<string, any>) {
  const payload: any = { processDefinitionKey: definitionKey };
  if (businessKey) payload.businessKey = businessKey;
  if (variables) {
    payload.variables = Object.entries(variables).map(([name, value]) => ({ name, value }));
  }
  const { data } = await flowable.post('/runtime/process-instances', payload);
  return data;
}

// ========== Tasks ==========
export async function listTasks(params: { assignee?: string; processDefinitionKey?: string } = {}) {
  const { data } = await flowable.get('/runtime/tasks', { params });
  return data.data || [];
}

// ========== Deployment Resources & BPMN XML ==========
export async function getProcessDefinition(id: string) {
  const { data } = await flowable.get(`/repository/process-definitions/${id}`);
  return data;
}

export async function listDeploymentResources(deploymentId: string) {
  const { data } = await flowable.get(`/repository/deployments/${deploymentId}/resources`);
  return data.data || [];
}

export async function getResourceXml(deploymentId: string, resourceId: string) {
  const res = await flowable.get(`/repository/deployments/${deploymentId}/resources/${resourceId}/data`, { responseType: 'text' });
  return res.data as string; // raw XML
}

// ========== Safe Delete Deployment ==========
interface ProcessDefinition {
  id: string;
  key: string;
  version: number;
  deploymentId: string;
}
interface ProcessInstance { id: string; processDefinitionId: string; businessKey?: string }

// Fetch process definitions by deployment
async function getDefinitionsByDeployment(deploymentId: string): Promise<ProcessDefinition[]> {
  const { data } = await flowable.get('/repository/process-definitions', { params: { deploymentId } });
  return data.data || [];
}

// Fetch running instances for a given process definition id
async function getInstancesByDefinitionId(procDefId: string): Promise<ProcessInstance[]> {
  const { data } = await flowable.get('/runtime/process-instances', { params: { processDefinitionId: procDefId } });
  return data.data || [];
}

// Delete a single process instance (exported for UI usage)
export async function deleteProcessInstance(instanceId: string, reason = 'user_cancel', cascade = false) {
  const params: any = { deleteReason: reason };
  if (cascade) params.cascade = true; // Flowable 支持 cascade 参数删除关联执行/任务
  await flowable.delete(`/runtime/process-instances/${instanceId}`, { params });
}

/**
 * Safely delete a deployment:
 * 1. Find all process definitions under deployment
 * 2. For each definition, delete all running instances
 * 3. Delete the deployment itself
 */
export async function safeDeleteDeployment(deploymentId: string): Promise<{ definitions: number; instancesDeleted: number }> {
  const defs = await getDefinitionsByDeployment(deploymentId);
  let instancesDeleted = 0;
  for (const d of defs) {
    const instances = await getInstancesByDefinitionId(d.id);
    for (const inst of instances) {
      await deleteProcessInstance(inst.id, 'deployment_cleanup');
      instancesDeleted++;
    }
  }
  await deleteDeployment(deploymentId);
  return { definitions: defs.length, instancesDeleted };
}
